//
//  SummaryController.m
//  ProcessTimeBudget
//
//  Created by isempty.chiu on 2010/9/14.
//  Copyright 2010 LifeMotion. All rights reserved.
//

#import "SummaryController.h"
#import "EventItem.h"
#import "EventController.h"
#import "ProcessMonitor.h"
#import "CommonFunc.h"

@implementation SummaryController
@synthesize summaryTable;
@synthesize budgetPercentLabel;
@synthesize occupancyPercentLabel;
@synthesize summaryTypeSeg;
@synthesize budgetValue;
@synthesize budgetSlider;

static SummaryController* summaryControllerInstance = nil;
+(SummaryController*) sharedController
{	
	return summaryControllerInstance;
}

-(id)init
{
	self = [super init];
	if(self)
	{
		selectedItemBudget_ = 0;
		alphabetSort_ = nil;
		valueSort_ = nil;	
		tableContent_ = [[NSMutableArray alloc] init];
		
		CandidateEventName_ = nil;
	}
	
	summaryControllerInstance = self;
	
	//Notification
	[[NSNotificationCenter defaultCenter] addObserver:self
											 selector:@selector(updateSummary)
												 name:@"RecordChanged" object:nil];	
	
	[[NSNotificationCenter defaultCenter] addObserver:self
											 selector:@selector(updateSummary)
												 name:@"EventChanged" object:nil];	
	
	[[NSNotificationCenter defaultCenter] addObserver:self
											 selector:@selector(eventCountChanged)
												 name:@"EventCountChanged" object:nil];	
	return self;
}

-(void)dealloc
{	
	//Notification
	[[NSNotificationCenter defaultCenter] removeObserver:self];	
	
	//UI Control
	[summaryTable release];
	[budgetPercentLabel release];
	[occupancyPercentLabel release];
	[summaryTypeSeg release];
	[budgetValue release];
	[budgetSlider release];
	
	//SortDescription
	if(alphabetSort_)
		[alphabetSort_ release];
	if(valueSort_)
		[valueSort_ release];
	
	//others
	if(tableContent_)
	{
		[tableContent_ removeAllObjects];
		[tableContent_ release];
	}
	
	[super dealloc];
}

@synthesize selectedItemBudget = selectedItemBudget_;

enum enumSummaryType {
	ST_UNKNOWN = 0,
	ST_CURRENT,
	ST_EVENT,
	ST_PROCESS
};

-(int)getSummaryType
{
	if([summaryTypeSeg isSelectedForSegment:0])
		return ST_CURRENT;
	else if([summaryTypeSeg isSelectedForSegment:1])
		return ST_EVENT;
	else if([summaryTypeSeg isSelectedForSegment:2])
		return ST_PROCESS;
	else
		return ST_UNKNOWN;
}

-(int)getNumberOfRowsForCurrentType
{
	if([EventController sharedController].CurrentEvent && [EventController sharedController].CurrentEvent.ProcessItemList)
		return [[EventController sharedController].CurrentEvent.ProcessItemList count];
	else {
		return 0;
	}
}

-(id)getValueAtRowForCurrentType:(int)row forKey:(NSString*)key
{
	id processItem;
	if([tableContent_ count] > 0)
		processItem = [tableContent_ objectAtIndex:row];
	else
		processItem = [[EventController sharedController].CurrentEvent.ProcessItemList objectAtIndex:row];

	if(processItem == nil)
	{
		//error happens
		[[NSUserDefaults standardUserDefaults] setObject:[NSString stringWithFormat:@"Error happen on getValueAtRowForCurrentType: %d",[tableContent_ count]] forKey:@"SummaryLog"];
		[[NSUserDefaults standardUserDefaults] synchronize];
		
		return nil;
	}
	
	NSString* name = [processItem valueForKey:@"Name"];
	NSInteger duration = [[processItem valueForKey:@"Duration"] integerValue];
	float budget = [[processItem valueForKey:@"Budget"] floatValue];
	
	if([key isEqualToString:@"Name"])
	{
		return name;
	}
	else if([key isEqualToString:@"Occupancy"])
	{
		if([EventController sharedController].CurrentEvent.Duration == 0)
			return [NSNumber numberWithInt:0];
		else
			return [NSNumber numberWithInt:(int)(100.0 * ((float)duration / (float)[EventController sharedController].CurrentEvent.Duration))];
	}
	else if([key isEqualToString:@"Budget"])
	{
		if(budget == 0)
			return [NSNumber numberWithInt:100];
		else
			return [NSNumber numberWithInt:(int)(100.0 * ((float)duration / (float)(budget * 3600.0)))];		
	}
	else {
		return nil;
	}
}

-(int)getNumberOfRowsForEventType
{
	return [[EventController sharedController].EventList count];
}

-(id)getValueAtRowForEventType:(int)row forKey:(NSString*)key
{
	EventItem* item;
	if([tableContent_ count] > 0)
		item = [tableContent_ objectAtIndex:row];
	else
		item = [[EventController sharedController].EventList objectAtIndex:row];
	if([key isEqualToString:@"Name"])
	{
		return item.Name;
	}
	else if([key isEqualToString:@"Occupancy"])
	{
		if([ProcessMonitor sharedProcMonitor].RunningTime == 0)
			return [NSNumber numberWithInt:0];
		else
			return [NSNumber numberWithInt:(int)(100.0 * ((float)item.Duration / (float)[ProcessMonitor sharedProcMonitor].RunningTime))];
	}
	else if([key isEqualToString:@"Budget"])
	{
		if(item.Budget == 0)
			return [NSNumber numberWithInt:100];
		else
			return [NSNumber numberWithInt:(int)(100.0 * ((float)item.Duration / (float)(item.Budget * 3600.0)))];		
	}
	else {
		return nil;
	}
}

-(NSArray*)getUProcessList
{
	NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease];
	for(EventItem* eventItem in [EventController sharedController].EventList)
	{
		for(id item in eventItem.ProcessItemList)
		{
			[array addObject:item];
		}
	}
	
	if([array count] > 0)
	{
		return [array valueForKeyPath:@"@distinctUnionOfObjects.Name"];
	}	
	
	return nil;
}

-(int)getNumberOfRowsForProcessType
{
	NSArray* processList = [self getUProcessList];	
	if(processList != nil)
		return [processList count];
	
	return 0;
}

-(id)getValueAtRowForProcessType:(int)row forKey:(NSString*)key
{
	return nil;
}

- (int)numberOfRowsInTableView:(NSTableView *)aTableView
{
	NSTableColumn* column = [summaryTable tableColumnWithIdentifier:@"Name"];
	
	int number = 0;
	int type = [self getSummaryType];
	if(type == ST_CURRENT)
	{
		[column setEditable:NO];
		number = [self getNumberOfRowsForCurrentType];
	}
	else if(type == ST_EVENT)
	{
		[column setEditable:YES];	
		number = [self getNumberOfRowsForEventType];
	}
	else if(type == ST_PROCESS)
	{
		[column setEditable:NO];
		number = 0;//[self getNumberOfRowsForProcessType];
	}
	
	if(valueSort_ == nil)
	{
		valueSort_ = [[NSSortDescriptor alloc] initWithKey:@"Duration" ascending:NO selector:@selector(compare:)];
		[[summaryTable tableColumnWithIdentifier:@"Occupancy"] setSortDescriptorPrototype:valueSort_];
		alphabetSort_ = [[NSSortDescriptor alloc] initWithKey:@"Name" ascending:NO selector:@selector(localizedCompare:)];
		[[summaryTable tableColumnWithIdentifier:@"Name"] setSortDescriptorPrototype:alphabetSort_];
	}
	return number;
}

- (void)prepareTableContent
{
	if([tableContent_ count] > 0)
	{
		[tableContent_ removeAllObjects];
	}
	
	int type = [self getSummaryType];
	if(type == ST_CURRENT)
	{
		for(id item in [EventController sharedController].CurrentEvent.ProcessItemList)
			[tableContent_ addObject:item];
	}
	else if(type == ST_EVENT)
	{
		for(id item in [EventController sharedController].EventList)
			[tableContent_ addObject:item];
	}
	else if(type == ST_PROCESS)
	{
	}	
	
	[tableContent_ sortUsingDescriptors:[summaryTable sortDescriptors]];
}

- (void)tableView:(NSTableView *)aTableView sortDescriptorsDidChange:(NSArray *)oldDescriptors
{
	[summaryTable deselectRow:[summaryTable selectedRow]];
	[self prepareTableContent];	
    [summaryTable reloadData];
}

- (id)     tableView:(NSTableView *) aTableView
objectValueForTableColumn:(NSTableColumn *) aTableColumn
				 row:(int) rowIndex
{
	int type = [self getSummaryType];
	if(type == ST_CURRENT)
	{
		return [self getValueAtRowForCurrentType:rowIndex forKey:[aTableColumn identifier]];
	}
	else if(type == ST_EVENT)
	{
		return [self getValueAtRowForEventType:rowIndex forKey:[aTableColumn identifier]];
	}
	else if(type == ST_PROCESS)
	{		
		return nil;
	}
	
	return nil;
}

- (void)updateOccupancy: (NSInteger)duration
{
	int percentage = 0;
	int base = 0;
	int summaryType = [self getSummaryType];
	if(summaryType == ST_CURRENT)
	{
		base = [EventController sharedController].CurrentEvent.Duration;
	}
	else if(summaryType == ST_EVENT)
	{
		base = [ProcessMonitor sharedProcMonitor].RunningTime;
	}
	else if(summaryType == ST_PROCESS)
	{
		base = [ProcessMonitor sharedProcMonitor].RunningTime;
	}
	
	if(base == 0)
		percentage = 0;
	else
		percentage = ((float)duration / (float)base) * 100;

	NSString* durationString = [CommonFunc getStringFromTimeInterval:duration];
	[occupancyPercentLabel setStringValue:[NSString stringWithFormat:@"%@ (%d%%)", durationString, percentage]];
	[durationString release];	
}

- (void)updateBudget: (float)budget byDuration:(NSInteger)duration 
{
	if(budget == 0)
	{
		[budgetPercentLabel setStringValue:[NSString stringWithFormat:@" "]];
		return;
	}
	
	budget = budget * 3600.0;
	NSInteger overDuration = 0;
	NSInteger remainDuration = 0;
	if(duration > budget)
	{
		overDuration = duration - budget; 
		[budgetPercentLabel setStringValue:[NSString stringWithFormat:@"(%d%%, %.2f hours over)", (int)((float)duration / ((float)budget) * 100.0), (float)overDuration / 3600.0]];
	}
	else 
	{
		remainDuration = budget - duration; 
		[budgetPercentLabel setStringValue:[NSString stringWithFormat:@"(%d%%, %.2f hours remaining)", (int)((float)duration / ((float)budget) * 100.0), (float)remainDuration / 3600.0]];
	}
}

-(void)updateSummary
{
	if([summaryTable selectedRow] >= 0)
	{
		[summaryTable deselectRow:[summaryTable selectedRow]];
		[self updateOccupancy:0];
		[self updateBudget:0 byDuration:0];
		[budgetSlider setEnabled:NO];	
	}
	if([self numberOfRowsInTableView:summaryTable] == 0)
	{
		[budgetSlider setEnabled:NO];	
	}
	
	if([self getSummaryType] == ST_PROCESS)
	{
		[budgetSlider setHidden:YES];
		[budgetPercentLabel setHidden:YES];		
		[budgetValue setHidden:YES];	
	}
	else 
	{
		[budgetSlider setHidden:NO];
		[budgetPercentLabel setHidden:NO];		
		[budgetValue setHidden:NO];	
	}

	if ([tableContent_ count] > 0) {
		[self prepareTableContent];
	}
	[summaryTable reloadData];
}

- (id)getSelectedItem
{
	if([summaryTable selectedRow] >= 0)
	{
		if([tableContent_ count] > 0)
		{
			//sorted
			return [tableContent_ objectAtIndex:[summaryTable selectedRow]];
		}
		else {
			//not-sorted
			NSString* selectedName = nil;
			int type = [self getSummaryType];
			{
				if(type == ST_CURRENT)
				{
					selectedName = [self getValueAtRowForCurrentType:[summaryTable selectedRow] forKey:@"Name"];
				}
				else if(type == ST_EVENT)
				{
					selectedName = [self getValueAtRowForEventType:[summaryTable selectedRow] forKey:@"Name"];
				}
				else if(type == ST_PROCESS)
				{
					return nil;
				}
				
				NSMutableArray* itemArray;
				if(type == ST_EVENT)
				{
					itemArray = [EventController sharedController].EventList;
				}
				else if(type == ST_CURRENT)
				{
					itemArray = [EventController sharedController].CurrentEvent.ProcessItemList;
				}
				
				for(id item in itemArray)
				{
					if([[item valueForKey:@"Name"] isEqualToString:selectedName])
						return item;
				}
			}		
		}
	}
	return nil;
}

-(NSString*) CandidateEventName
{
	return CandidateEventName_;
}

- (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject
   forTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
{
	//validate new value
	CandidateEventName_ = [[self getSelectedItem] valueForKey:@"Name"];
	[self willChangeValueForKey:@"CandidateEventName"];
	CandidateEventName_ = anObject;
	[self didChangeValueForKey:@"CandidateEventName"];
}

- (void)tableViewSelectionDidChange:(NSNotification *)aNotification
{
	NSInteger duration = 0;
	float budget = 0;
	id item = [self getSelectedItem];
	if(item)
	{
		duration = [[item valueForKey:@"Duration"] integerValue];
		budget = [[item valueForKey:@"Budget"] floatValue];
	}
	
	[self updateOccupancy:duration];
	[self updateBudget:budget byDuration:duration];

	[self willChangeValueForKey:@"selectedItemBudget"];
	selectedItemBudget_ = budget;
	[self didChangeValueForKey:@"selectedItemBudget"];
	
	[budgetSlider setEnabled:item != nil ? YES : NO];
}

- (void) eventCountChanged
{
	[self prepareTableContent];
}

- (IBAction)budgetChangeAction:(id)sender
{
	NSInteger duration = 0;
	id item = [self getSelectedItem];
	if(item)
	{
		duration = [[item valueForKey:@"Duration"] integerValue];
		[item setValue:[NSNumber numberWithFloat:selectedItemBudget_] forKey:@"Budget"];
	}
	
	[self updateBudget:selectedItemBudget_ byDuration:duration];
	[summaryTable reloadData];
}

- (IBAction)summaryTypeSelected:(id)sender
{
	NSTableColumn* column = [summaryTable tableColumnWithIdentifier:@"Name"];
	int type = [self getSummaryType];
	if(type == ST_EVENT)
	{
		[[column headerCell] setStringValue:@"Event"];
	}
	else 
	{
		[[column headerCell] setStringValue:@"Process"];		
	}
		
	[self prepareTableContent];
	[self updateSummary];
}

@end
